package com.richard.library.http.request;


import com.richard.library.http.converter.JsonConverter;
import com.richard.library.http.dict.RequestType;
import com.richard.library.http.model.UploadFileModel;
import com.richard.library.http.request.upload.UploadFileProgressListener;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;


/**
 * <pre>
 * Description : 请求构造器
 * Author : admin-richard
 * Date : 2018/3/1 15:43
 * Changelog:
 * Version            Date            Author              Detail
 * ----------------------------------------------------------------------
 * 1.0         2018/3/1 15:43     admin-richard         new file.
 * </pre>
 */
public class RequestBuilder {

    /**
     * 处理请求参数
     */
    private ProcessRequestEvent processRequestEvent;

    /**
     * 处理响应数据
     */
    private ProcessResponseEvent processResponseEvent;

    //---------------------------以下为网络请求相关参数---------------------------

    /**
     * 请求类型
     */
    private final RequestType requestType;

    /**
     * 请求URL
     */
    private String url;

    /**
     * 请求头信息
     */
    private final Map<String, Object> header = new HashMap<>();

    /**
     * 请求参数
     */
    private final Map<String, Object> paramsMap = new HashMap<>();

    /**
     * 请求参数
     */
    private String paramsStr;

    /**
     * 上传文件
     */
    private List<UploadFileModel> files;

    /**
     * 文件上传进度监听
     */
    private UploadFileProgressListener uploadFileProgressListener;

    /**
     * 是否允许重定向 默认允许重定向
     */
    private boolean followRedirect = true;

    /**
     * 响应是否以流的形式返回
     */
    private boolean isStreaming;

    /**
     * 是否将请求参数转换为xml
     */
    private boolean isConvertXml;

    /**
     * 当前设置的请求超时时间
     */
    private Long timeout;

    /**
     * 当前设置的请求超时时间单位
     */
    private TimeUnit timeoutUnit;


    /**
     * 初始实例化RequestBuilder
     *
     * @param requestType 请求类型
     */
    public static RequestBuilder init(RequestType requestType) {
        return new RequestBuilder(requestType);
    }

    /**
     * 构造
     */
    private RequestBuilder(RequestType requestType) {
        this.requestType = requestType;
    }

    /**
     * 获取http header map
     */
    public Map<String, Object> getHeader() {
        return header;
    }

    /**
     * 获取请求参数map
     */
    public Map<String, Object> getParamsMap() {
        return paramsMap;
    }

    /**
     * 获取请求参数字符串
     */
    public String getParamsStr() {
        return paramsStr;
    }

    /**
     * 设置URL地址参数
     *
     * @param url url地址
     */
    public RequestBuilder setUrl(String url) {
        this.url = url;
        return this;
    }

    /**
     * 设置http header map
     *
     * @param header header
     */
    public RequestBuilder setHeader(Map<String, Object> header) {
        this.header.clear();
        if (header != null) {
            this.header.putAll(header);
        }
        return this;
    }

    /**
     * 添加header
     *
     * @param key   header key
     * @param value header value
     */
    public RequestBuilder addHeader(String key, Object value) {
        this.header.put(key, value);
        return this;
    }

    /**
     * 添加header map
     *
     * @param header header map
     */
    public RequestBuilder addHeader(Map<String, Object> header) {
        this.header.putAll(header);
        return this;
    }

    /**
     * 设置请求参数map
     *
     * @param params 请求参数
     */
    public RequestBuilder setParams(Map<String, Object> params) {
        if (paramsStr != null) {
            throw new IllegalArgumentException("Only one of Map type parameter and String type parameter can be set.");
        }
        this.paramsMap.clear();
        if (params != null) {
            this.paramsMap.putAll(params);
        }
        return this;
    }

    /**
     * 添加一个请求参数
     *
     * @param key   Param key
     * @param value Param value
     */
    public RequestBuilder addParam(String key, Object value) {
        if (paramsStr != null) {
            throw new IllegalArgumentException("Only one of Map type parameter and String type parameter can be set.");
        }
        this.paramsMap.put(key, value);
        return this;
    }

    /**
     * 添加一个请求参数
     *
     * @param params 请求参数map
     */
    public RequestBuilder addParam(Map<String, Object> params) {
        if (paramsStr != null) {
            throw new IllegalArgumentException("Only one of Map type parameter and String type parameter can be set.");
        }
        this.paramsMap.putAll(params);
        return this;
    }

    /**
     * 设置请求参数字符串
     *
     * @param params 请求参数字符串
     */
    public RequestBuilder setParams(String params) {
        if (!paramsMap.isEmpty()) {
            throw new IllegalArgumentException("Only one of Map type parameter and String type parameter can be set.");
        }
        this.paramsStr = params;
        return this;
    }

    /**
     * 设置上传文件列表
     *
     * @param files                      文件列表
     * @param uploadFileProgressListener 上传文件进度监听
     */
    public RequestBuilder setFiles(List<UploadFileModel> files, UploadFileProgressListener uploadFileProgressListener) {
        this.files = files;
        this.uploadFileProgressListener = uploadFileProgressListener;
        return this;
    }

    /**
     * 设置是否允许重定向
     */
    public RequestBuilder setFollowRedirect(boolean followRedirect) {
        this.followRedirect = followRedirect;
        return this;
    }

    /**
     * 设置是否将请求参数转换为xml
     */
    public RequestBuilder setConvertXml(boolean convertXml) {
        this.isConvertXml = convertXml;
        return this;
    }

    /**
     * 设置响应是否以流的形式返回
     */
    public RequestBuilder setStreaming(boolean streaming) {
        this.isStreaming = streaming;
        return this;
    }

    /**
     * 设置当前请求超时时间
     * @param timeout 时间数
     * @param unit    时间数单位
     */
    public RequestBuilder timeout(long timeout, TimeUnit unit){
        this.timeout = timeout;
        this.timeoutUnit = unit;
        return this;
    }

    /**
     * 设置处理请求参数事件
     */
    public RequestBuilder setProcessRequestEvent(ProcessRequestEvent processRequestEvent) {
        this.processRequestEvent = processRequestEvent;
        return this;
    }

    /**
     * 设置请求响应数据处理事件
     */
    public RequestBuilder setProcessResponseEvent(ProcessResponseEvent processResponseEvent) {
        this.processResponseEvent = processResponseEvent;
        return this;
    }

    public ProcessRequestEvent getProcessRequestEvent() {
        return processRequestEvent;
    }

    public ProcessResponseEvent getProcessResponseEvent() {
        return processResponseEvent;
    }

    public RequestType getRequestType() {
        return requestType;
    }

    public String getUrl() {
        return url;
    }

    public List<UploadFileModel> getFiles() {
        return files;
    }

    public UploadFileProgressListener getUploadFileProgressListener() {
        return uploadFileProgressListener;
    }

    public boolean isFollowRedirect() {
        return followRedirect;
    }

    public boolean isStreaming() {
        return isStreaming;
    }

    public boolean isConvertXml() {
        return isConvertXml;
    }

    public Long getTimeout() {
        return timeout;
    }

    public TimeUnit getTimeoutUnit() {
        return timeoutUnit;
    }

    @Override
    public String toString() {
        return "RequestBuilder{" +
                "processRequestEvent=" + processRequestEvent +
                "processResponseEvent=" + processResponseEvent +
                ", requestType=" + requestType +
                ", url='" + url + '\'' +
                ", header=" + JsonConverter.toJson(header) +
                ", paramsMap=" + JsonConverter.toJson(paramsMap) +
                ", paramsStr='" + paramsStr + '\'' +
                ", files=" + JsonConverter.toJson(files) +
                ", uploadFileProgressListener=" + uploadFileProgressListener +
                ", followRedirect=" + followRedirect +
                ", isStreaming=" + isStreaming +
                ", isConvertXml=" + isConvertXml +
                '}';
    }

    /**
     * build
     */
    public RequestService build() {
        return new RequestService(this);
    }
}
